package com.wwz.config;

import com.baomidou.mybatisplus.enums.DBType;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.plugins.pagination.DialectFactory;
import com.baomidou.mybatisplus.plugins.pagination.PageHelper;
import com.baomidou.mybatisplus.plugins.pagination.Pagination;
import com.baomidou.mybatisplus.plugins.parser.ISqlParser;
import com.baomidou.mybatisplus.plugins.parser.SqlInfo;
import com.baomidou.mybatisplus.toolkit.JdbcUtils;
import com.baomidou.mybatisplus.toolkit.PluginUtils;
import com.baomidou.mybatisplus.toolkit.SqlUtils;
import com.baomidou.mybatisplus.toolkit.StringUtils;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.RowBounds;

import java.sql.Connection;
import java.util.Properties;

@Intercepts({@Signature(
        type = StatementHandler.class,
        method = "prepare",
        args = {Connection.class, Integer.class}
)})
public class PaginationInterceptorImpl extends PaginationInterceptor {
    private ISqlParser sqlParser;
    private boolean overflowCurrent = false;
    private String dialectType;
    private String dialectClazz;
    private boolean localPage = false;


    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler) PluginUtils.realTarget(invocation.getTarget());
        MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
        MappedStatement mappedStatement = (MappedStatement)metaObject.getValue("delegate.mappedStatement");
        if (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) {
            return invocation.proceed();
        } else {
            Integer total = 0;
            RowBounds rowBounds = (RowBounds)metaObject.getValue("delegate.rowBounds");
            if (rowBounds != null && rowBounds != RowBounds.DEFAULT) {
                BoundSql boundSql = (BoundSql)metaObject.getValue("delegate.boundSql");
                String originalSql = boundSql.getSql();
                Connection connection = (Connection)invocation.getArgs()[0];
                DBType dbType = StringUtils.isNotEmpty(this.dialectType) ? DBType.getDBType(this.dialectType) : JdbcUtils.getDbType(connection.getMetaData().getURL());
                if (rowBounds instanceof Pagination) {
                    Pagination page = (Pagination)rowBounds;
                    boolean orderBy = true;
                    if (page.isSearchCount()) {
                        SqlInfo sqlInfo = SqlUtils.getCountOptimize(this.sqlParser, originalSql);
                        orderBy = sqlInfo.isOrderBy();
                        this.queryTotal(this.overflowCurrent, sqlInfo.getSql(), mappedStatement, boundSql, page, connection);
                        if ((total = page.getTotal()) <= 0) {
                            return invocation.proceed();
                        }
                    }
                    String buildSql = SqlUtils.concatOrderBy(originalSql, page, orderBy).replace("LIMIT ?","");
                    originalSql = DialectFactory.buildPaginationSql(page, buildSql, dbType, this.dialectClazz);
                } else {
                    originalSql = DialectFactory.buildPaginationSql((RowBounds)rowBounds, originalSql, dbType, this.dialectClazz);
                }

                metaObject.setValue("delegate.boundSql.sql", originalSql);
                metaObject.setValue("delegate.rowBounds.offset", Integer.valueOf(0));
                metaObject.setValue("delegate.rowBounds.limit", 2147483647);
                return invocation.proceed();
            }else{
                return invocation.proceed();
            }


        }
    }

    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }
    @Override
    public void setProperties(Properties properties) {

    }

    public ISqlParser getSqlParser() {
        return sqlParser;
    }



    public boolean isOverflowCurrent() {
        return overflowCurrent;
    }


    public String getDialectType() {
        return dialectType;
    }


    public String getDialectClazz() {
        return dialectClazz;
    }


    public boolean isLocalPage() {
        return localPage;
    }


}
